/*
 * @Author: FanWeiHua
 * @Date: 2021-06-27 14:42:22
 * @LastEditTime: 2022-08-10 18:44:22
 * @Description: 公共方法类
 */
import QS from 'qs';
import moment from 'moment';
import _ from 'lodash';

/**
 * 获取行政级别
 */
export const getSplitJgdm = dm => {
  if (!dm) {
    return '';
  }
  let [idx, temp] = [dm.length - 1, ''];
  for (let i = dm.length - 1; i >= 0; i = i - 2) {
    temp = dm.substring(i - 1, i + 1);
    if (temp !== '00') {
      break;
    }
    idx = i - 2;
  }
  let [returnValue, level] = [dm.substring(0, idx + 1), 0];
  if (returnValue.length === 2) {
    level = 1; // 省
  } else if (returnValue.length === 4) {
    level = 2; // 市
  } else if (returnValue.length === 6) {
    level = 3; // 区县
  } else if (returnValue.length === 8) {
    level = 4; // 派出所
  } else if (returnValue.length === 10) {
    level = 5; // 责任区
  }
  return { returnValue, level };
};
/**
 * 获取元素到可视窗口的距离
 */
export const handleGetElmOffsetTop = elm => {
  if (!elm || elm.nodeType !== 1) {
    throw Error('参数必须为元素');
  }
  let offsetTop = elm.offsetTop;
  let parentNode = elm.offsetParent;
  while (parentNode !== null) {
    offsetTop += parentNode.offsetTop;
    parentNode = parentNode.offsetParent;
  }
  return offsetTop;
};
/**
 * 删除指定字符
 * @param string
 * @param re
 */
export const removeGivenString = (string, re) => {
  return string.split(re).join('');
};
/**
 * 拼接http的get请求获取url
 */
export const getSplitHttpUrl = obj => {
  let url = '?';
  Object.keys(obj).forEach((key, index) => {
    if (parseInt(index) === 0) {
      if (typeof obj[key] !== 'undefined') url += key + '=' + obj[key];
    } else {
      if (typeof obj[key] !== 'undefined') url += '&' + key + '=' + obj[key];
    }
  });
  return url;
};
/**
 * 将数组切割成指定长度的子数组
 */
export const handleSliceArry = (array, size) => {
  const result = [];
  const len = array.length;
  const step = Math.ceil(len / size);
  if (!len) {
    return result;
  }
  for (let i = 0; i < step; i++) {
    const start = i * size;
    const end = (i + 1) * size;
    const tempArray = array.slice(start, end);
    result.push(tempArray);
  }
  return result;
};
/**
 * @description: 判断是否是图片路径
 * @param imgUrl {String} 图片URL地址
 * @return: Boolean
 */
export const handleGetImgPath = imgUrl => {
  if (!imgUrl) {
    return false;
  }
  // 常见图片的扩展名
  const imgSuffixs = ['.jpg', '.png', '.jpeg', '.gif', '.svg', '.bmp', '.jpe'];
  // 当前图片的扩展名
  const imgSuffix = imgUrl.substring(imgUrl.lastIndexOf('.'));
  return imgSuffixs.indexOf(imgSuffix.toLowerCase()) !== -1;
};
/**
 * 生成图层uuid，保证每个图层有唯一一个uuid
 */
export const getUuid = () => {
  const S4 = () => {
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  };
  return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
};
/**
 * 四舍五入保留有效数字
 */
export const formatting = (src, pos) => {
  return Math.round(src * Math.pow(10, pos)) / Math.pow(10, pos);
};
/**
 * 在多个地址中随机获取一个地址，一旦获得地址后，后续所以访问都用此地址
 * @param urls(array)   地址数组
 */
export const getHashUrl = urls => {
  if (urls.length < 1) {
    return '' + urls;
  }
  const u = sessionStorage.getItem('ws_url');
  if (u && u !== '') {
    return u;
  } else {
    const rand = Math.floor(Math.random() * urls.length);
    const data = urls.slice(rand, 1)[0];
    sessionStorage.setItem('ws_url', data);
    return data;
  }
};
/**
 * 高频事件触发，但在n秒内只会执行一次，所以节流会稀释函数的执行频率。
 * @param fn  函数
 * @param ms  时间段内
 * @returns {Function}
 */
export const throttle = (fn, ms) => {
  let canRun = true; // 通过闭包保存一个标记
  return args => {
    if (!canRun) return; // 在函数开头判断标记是否为true，不为true则return
    canRun = false; // 立即设置为false
    setTimeout(() => {
      // 将外部传入的函数的执行放在setTimeout中
      fn.apply(this, args);
      /* 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
      当定时器没有执行的时候标记永远是false，在开头被return掉 */
      canRun = true;
    }, ms);
  };
};
/**
 * 触发高频事件后n秒内函数只会执行一次，如果n秒内高频事件再次被触发，则重新计算时间。
 * @param fn
 * @param ms
 * @returns {Function}
 */
export const debounce = (fn, ms) => {
  let timeout = null; // 创建一个标记用来存放定时器的返回值
  return args => {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话，就不会执行 fn 函数
    timeout = setTimeout(() => {
      fn.apply(this, args);
    }, ms);
  };
};
/**
 * 动态加载css和js文件
 */
export const dynamicLoading = {
  css: function (path) {
    if (!path || path.length === 0) {
      throw new Error('argument "path" is required !');
    }
    const head = document.getElementsByTagName('head')[0];
    const link = document.createElement('link');
    link.href = path;
    link.rel = 'stylesheet';
    head.appendChild(link);
  },
  js: function (path) {
    if (!path || path.length === 0) {
      throw new Error('argument "path" is required !');
    }
    const head = document.getElementsByTagName('head')[0];
    const script = document.createElement('script');
    script.src = path;
    head.appendChild(script);
  },
};
/**
 * 根据路由path获取路由对象
 * @param path
 * @param list
 */
export const getRouteByPath = (path, list) => {
  let [route, state] = ['', false];
  for (let i = 0, lens = list.length; i < lens; i++) {
    if (path === list[i].path) {
      route = list[i];
      state = true;
      break;
    } else {
      if (list[i].routes && list[i].routes.length > 0) {
        const objDate = getRouteByPath(path, list[i].routes);
        if (objDate.state) {
          route = objDate.route;
          state = true;
          break;
        }
      }
    }
  }
  return { route, state };
};
/**
 * 路径分割成有效数组对象排序
 */
export const arraySegmentationByRouter = list => {
  const [obj, listRoute] = [{}, []];
  for (let i = 0, lens = list.length; i < lens; i++) {
    if (obj[list[i].order] instanceof Array) {
      obj[list[i].order].push(list[i]);
    } else {
      obj[list[i].order] = [];
      obj[list[i].order].push(list[i]);
    }
  }
  const listObj = Object.keys(obj);
  if (listObj.length > 0) {
    Object.keys(obj).map(key => {
      listRoute.push(obj[key]);
    });
  }
  return listRoute;
};
/**
 * 数组根据有效规则分割成对象
 */
export const arraySegmentation = (list, num) => {
  const [obj, sliceN] = [
    {},
    list.length / num <= 1 && list.length / num > 0
      ? 0
      : parseInt(list.length % num > 0 ? list.length / num + 1 : list.length / num),
  ];
  if (sliceN === 0) {
    obj[0] = list;
  } else {
    for (let i = 0; i < sliceN; i++) {
      if (i === 0) {
        obj[i] = list.slice(0, num);
      } else {
        obj[i] = list.slice(num * i, num * (i + 1));
      }
    }
  }
  return obj;
};

/**
 * 获取URL地址参数
 */
export const getUrlParam = (url = '') => {
  if (!url) return {};
  // 将URL地址?分隔
  const paramString = url.indexOf('?') === -1 ? url : url.split('?')[1];
  return QS.parse(paramString);
};
/**
 * 设置URL地址参数
 */
export const setUrlParam = (url, params) => {
  return url.indexOf('?') !== -1
    ? // URL地址自带参数
      `${url}&${QS.stringify(params)}`
    : // URL地址无参数
      `${url}?${QS.stringify(params)}`;
};
/**
 * 根据key获取对应对象
 */
export const getObjByKey = (key, list) => {
  let [obj, state] = ['', false];
  for (let i = 0, lens = list.length; i < lens; i++) {
    if (key === list[i].key) {
      obj = list[i];
      state = true;
      break;
    } else {
      if (list[i].children && list[i].children.length > 0) {
        const objDate = getObjByKey(key, list[i].children);
        if (objDate.state) {
          obj = objDate.obj;
          state = true;
          break;
        }
      }
    }
  }
  return { obj, state };
};
/**
 * 根据路由地址获取对应对象
 */
export const getObjByPath = (path, list) => {
  let obj;
  for (let i = 0, lens = list.length; i < lens; i++) {
    if (path === list[i].path) {
      obj = list[i];
      break;
    } else {
      if (list[i].children && list[i].children.length > 0) {
        const objDate = getObjByPath(path, list[i].children);
        if (objDate) {
          obj = objDate;
          break;
        }
      }
    }
  }
  return obj;
};
/**
 * 进入全屏
 */
export const toFullScreen = () => {
  const el = document.documentElement;
  const rfs = el.requestFullScreen || el.webkitRequestFullScreen || el.mozRequestFullScreen || el.msRequestFullScreen;
  if (typeof rfs !== 'undefined' && rfs) {
    rfs.call(el);
  } else if (typeof window.ActiveXObject !== 'undefined') {
    // for IE，这里其实就是模拟了按下键盘的F11，使浏览器全屏
    // eslint-disable-next-line no-undef
    const wscript = new ActiveXObject('WScript.Shell');
    if (wscript != null) {
      wscript.SendKeys('{F11}');
    }
  }
};
/**
 * 退出全屏
 */
export const exitFullScreen = () => {
  const el = document;
  const cfs = el.cancelFullScreen || el.webkitCancelFullScreen || el.mozCancelFullScreen || el.exitFullScreen;
  if (typeof cfs !== 'undefined' && cfs) {
    cfs.call(el);
  } else if (typeof window.ActiveXObject !== 'undefined') {
    // for IE，这里和fullScreen相同，模拟按下F11键退出全屏
    // eslint-disable-next-line no-undef
    const wscript = new ActiveXObject('WScript.Shell');
    if (wscript != null) {
      wscript.SendKeys('{F11}');
    }
  }
};
/**
 * 循环获取秒级时间
 * @param {*} timeString
 * @param {*} callBack
 */
export let loopSecondsTimeOut;
export const loopSeconds = (timeString, callBack) => {
  try {
    if (!timeString) {
      timeString = moment().format('YYYY-MM-DD HH:mm:ss');
    }
    const curTs = moment(timeString, 'YYYY-MM-DD HH:mm:ss').add(1, 'seconds').format('YYYY-MM-DD HH:mm:ss');
    if (callBack instanceof Function) {
      loopSecondsTimeOut = setTimeout(() => {
        loopSeconds(curTs, callBack);
      }, 1000);
      callBack(curTs);
    }
  } catch (e) {
    console.error(e);
    callBack('');
  }
};
/**
 * 获取唯一id
 */
export const getUid = () => {
  const S4 = () => {
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  };
  return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
};
/**
 * 获取字符串中的数字
 * @param text
 */
export const getNum = text => {
  return text.replace(/[^0-9]/gi, '');
};
/**
 * 数据深拷贝
 */
export const deepCopy = dataSource => {
  return _.deepCopy(dataSource);
};
/**
 * 数据浅拷贝
 */
export const clone = dataSource => {
  return _.clone(dataSource);
};
/**
 * 验证身份证号码
 * 15位：350424870506202
 * 18位：510902199311108496
 * 18位：51090219931110849X
 */
export const isCardNo = card => {
  const reg =
    /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/;
  return reg.test(card);
};

/**
 * 根据身份证获取出生年月日 YYYY-MM-DD
 * @param {string} card 身份证号码
 */
export const getBirthdatByIdCard = card => {
  let tmpStr = '';
  if (!isCardNo(card)) {
    console.error('身份证号码有误');
    return;
  }
  if (card.length === 15) {
    tmpStr = card.substring(6, 12);
    tmpStr = '19' + tmpStr;
    tmpStr = tmpStr.substring(0, 4) + '-' + tmpStr.substring(4, 6) + '-' + tmpStr.substring(6);
    return tmpStr;
  } else {
    tmpStr = card.substring(6, 14);
    tmpStr = tmpStr.substring(0, 4) + '-' + tmpStr.substring(4, 6) + '-' + tmpStr.substring(6);
    return tmpStr;
  }
};
/**
 * 判断身份证号码日期不能大于当前日期
 * @return {Boolean} true 正确的身份证  false 错误的身份证
 */
export const judgeIdCardBirth = card => {
  const birthday = getBirthdatByIdCard(card);
  const state = moment().isAfter(birthday);
  return state;
};

/**
 * 根据身份证号获取性别
 */
export const getSexByCard = idCard => {
  const state = isCardNo(idCard); // 判断是否为身份证
  if (!state) {
    return '';
  }
  if (parseInt(idCard.substr(16, 1)) % 2 === 1) {
    return '1';
  } else {
    return '2';
  }
};
/**
 * 拆分省市区
 */
export const splitArea = areaStr => {
  if (!areaStr) return;
  /**
   * 1、成都市彭州市天蓬镇（彭州市比较特殊，名字含有州）
   * 2、达州市渠县有庆镇 （渠县比较特殊，县前面只有一个字）
   */
  // 四川省的县 前面是单个字的
  const spicilArea = ['荣县', '泸县', '安县', '珙县', '高县', '达县', '渠县', '茂县', '理县'];
  // 找出地址中是否有这些特殊的县
  let isHaveSpacialArea = false;
  let allReg;
  for (let i = 0; i < spicilArea.length; i++) {
    if (areaStr.includes(spicilArea[i])) {
      isHaveSpacialArea = true;
      break;
    }
  }
  if (isHaveSpacialArea) {
    allReg =
      /([\u4e00-\u9fa5]{2,5}?(?:省|自治区|自治州|市))([\u4e00-\u9fa5]{1,7}?(?:市|区|县|州)){0,1}([\u4e00-\u9fa5]{2,7}?(?:市|区|县)){0,1}/;
  } else {
    allReg =
      /([\u4e00-\u9fa5]{2,5}?(?:省|自治区|自治州|市))([\u4e00-\u9fa5]{2,7}?(?:市|区|县|州)){0,1}([\u4e00-\u9fa5]{2,7}?(?:市|区|县)){0,1}/;
  }
  const res = areaStr.match(allReg);
  return res || [];
};
/**
 * 验证手机号
 */
export const phoneReg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/;
export const isPhoneNo = phoneNo => {
  return phoneReg.test(phoneNo);
};
/**
 * 验证手机号或者座机号
 */
export const phoneOrLandNoReg = /^[1][3,4,5,6,7,8,9][0-9]{9}$/; // 校验手机号和固定电话
const phone = /^1[3|4|5|6|7|8|9]\d{9}$/;
const ring = /^0\d{2,3}-?\d{7,8}$/;
const noAreaCodeRing = /\d{7,8}$/;
export const isPhoneOrLandNo = phoneNo => {
  // return phoneOrLandNoReg.test(phoneNo);
  return phone.test(phoneNo) || ring.test(phoneNo) || noAreaCodeRing.test(phoneNo);
};
/**
 * 验证车牌号
 */
export const plateNumberReg =
  /^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[a-zA-Z](([DF]((?![IO])[a-zA-Z0-9](?![IO]))[0-9]{4})|([0-9]{5}[DF]))|[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1})$/;
export const isPlateNumber = plateNumber => {
  if (!plateNumber) {
    console.error('请传入车牌号');
    return;
  }
  return plateNumberReg.test(plateNumber);
};
/**
 * 数组位置替换
 * @param {*} array 数组
 * @param {*} fromIndex 老的索引
 * @param {*} toIndex 新的索引
 */
export const arrayMoveMutable = (array, fromIndex, toIndex) => {
  const startIndex = fromIndex < 0 ? array.length + fromIndex : fromIndex;

  if (startIndex >= 0 && startIndex < array.length) {
    const endIndex = toIndex < 0 ? array.length + toIndex : toIndex;

    const [item] = array.splice(fromIndex, 1);
    array.splice(endIndex, 0, item);
  }
};
export const arrayMoveImmutable = (array, fromIndex, toIndex) => {
  array = [...array];
  arrayMoveMutable(array, fromIndex, toIndex);
  return array;
};
/**
 * 打开新的tab页，如果打开的是同域名的话，用该方法，因为这样可以保证，新打开的页面和原页面不占用同一个进程
 * @param url
 */
export const openNewWindow = url => {
  const a = document.createElement('a'); // 创建a标签
  a.setAttribute('href', url); // url即为需要打开的新页面的url
  a.setAttribute('target', '_blank'); // _blank新窗口打开
  a.setAttribute('rel', 'noopener noreferrer'); // 添加rel
  document.body.appendChild(a);
  a.click();
};
/**
 * 获取自定的DES算法在前端加密的key
 */
export const getCustomCryptoKeyByTime = time => {
  const keyArr = [
    't',
    'u',
    'v',
    'A',
    'E',
    '7',
    '8',
    'F',
    'G',
    'H',
    'D',
    'p',
    'K',
    'L',
    'g',
    'h',
    'M',
    '4',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    '2',
    '3',
    'Y',
    'Z',
    'a',
    'C',
    'f',
    'i',
    'j',
    'k',
    'l',
    'd',
    'e',
    'm',
    'I',
    'J',
    'n',
    'o',
    'B',
    'q',
    'r',
    's',
    'w',
    'x',
    'y',
    'V',
    'W',
    'X',
    'z',
    '0',
    '1',
    '5',
    'b',
    '6',
    'c',
    '9',
  ];
  time = time.split('-');
  time = time.join('');
  time = time.split('');
  if (Array.isArray(time)) {
    const arr = [];
    time.forEach(item => {
      item = parseInt(item);
      arr.push(keyArr[item]);
      arr.push(keyArr[item + item]);
    });
    return arr.join('');
  }
};
/**
 * 获取设备终端类型，移动端还是pc端
 */
export const getDeviceTerminalType = () => {
  let type = 'pc';
  if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
    type = 'mobile';
  }
  return type;
};
/**
 * 判断是否为formData数据
 */
export const isFormData = v => {
  return Object.prototype.toString.call(v) === '[object FormData]';
};
/**
 * 处理树形结构数据为antd支持的数据格式
 */
export const handleDataToAntdTreeData = treeData => {
  if (treeData?.length) {
    treeData.forEach(item => {
      item.title = item.label;
      item.key = item.value;
      if (item?.children?.length) {
        handleDataToAntdTreeData(item.children);
      }
    });
  }
  return treeData;
};
/**
 * 数组去除
 */
export const arrUnique = (arr, key = 'key') => {
  return arr.filter((item, index, arr) => {
    return arr.findIndex(cItem => cItem[key] === item[key]) === index;
  });
};
/**
 * 数组排序
 * @param {*} state 升序还是降序，true为升序，false为降序
 */
export const arraySort = (list, sort = 'px', state) => {
  list = list.sort((a, b) => {
    if (state) {
      if (a[sort] > b[sort]) {
        return 1;
      } else {
        return -1;
      }
    } else {
      if (a[sort] < b[sort]) {
        return 1;
      } else {
        return -1;
      }
    }
  });
  return list;
};
/**
 * 让元素滚动到可视区域
 * @param {String} className 类名
 */
export const toElmentView = async className => {
  if (!className) {
    console.error('请传入类名');
    return;
  }
  const el = await document.getElementsByClassName(className);
  el[0].scrollIntoView(true);
};
